home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xmessage
/
makeform.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-22
|
15KB
|
549 lines
/*
* xmessage - utility for querying users
*
* Copyright 1988,1991 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. M.I.T. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#define SCROLLBAR_WIDTH 14
#define SCROLLBAR_HEIGHT 14
extern char *malloc();
extern char *ProgramName;
extern Widget default_button_widget;
extern char *copy_stdin();
typedef struct _ButtonRecord {
char *name; /* button name */
char *filename; /* file to unlink on exit, or NULL */
int exitstatus; /* exit status for this button */
Boolean print_value; /* print button name on exit? */
Widget widget; /* button Command widget */
} ButtonRecord;
/*
* event handler to warp the pointer to the default button when the button
* is exposed.
*/
static XtEventHandler warp_to_button (w, closure, event, continue_to_dispatch)
Widget w; /* widget that was exposed */
XtPointer closure; /* ButtonRecord to warp pointer to */
XEvent *event; /* event */
Boolean *continue_to_dispatch; /* ignored */
{
ButtonRecord *br;
Arg args[3]; /* argument list */
Cardinal num_args;
Dimension width, height, b_width;
int x, y;
br = (ButtonRecord *) closure;
num_args = 0;
(void) XtSetArg(args[num_args], XtNwidth, &width); num_args++;
(void) XtSetArg(args[num_args], XtNheight, &height); num_args++;
(void) XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
(void) XtGetValues(br->widget, args, num_args);
width += 2 * b_width;
height += 2 * b_width;
x = width / 2;
y = height / 2;
XWarpPointer (XtDisplay(br->widget), None, XtWindow(br->widget),
0, 0, 0, 0, x, y);
XtRemoveEventHandler(w, ExposureMask, False, (XtEventHandler)warp_to_button,
(XtPointer) br);
}
/*
* compute width and height of message in terms of columns and lines
*/
static void get_message_dimensions (message, width, height)
char *message; /* message string to be displayed */
int *width; /* width needed to display string */
int *height; /* height needed to display string */
{
int lines, cols, maxcols;
char *cp;
*width = 0;
*height = 0;
lines = 0;
cols = 0;
maxcols = 0;
for (cp = message; *cp; cp++) {
switch (*cp)
{
case '\n':
lines++;
if (cols > maxcols) maxcols = cols;
cols = 0;
break;
case '\t':
cols = ((cols >> 3) + 1) << 3;
default:
cols++;
break;
}
}
if (cols > 0) {
lines++;
if (cols > maxcols) maxcols = cols;
}
*width = maxcols;
*height = lines;
}
/*
* compute width and height of file contents in terms of columns and lines
*/
static void get_file_dimensions (filename, width, height)
char *filename; /* file to be displayed */
int *width; /* width needed to display string */
int *height; /* height needed to display string */
{
int lines, cols, maxcols;
int c;
FILE *fp;
*width = 0;
*height = 0;
fp = fopen (filename, "r");
if (!fp) return;
lines = 0;
cols = 0;
maxcols = 0;
while ((c = getc(fp)) != EOF) {
switch (c)
{
case '\n':
lines++;
if (cols > maxcols)
maxcols = cols;
cols = 0;
break;
case '\t':
cols = ((cols >> 3) + 1) << 3;
default:
cols++;
break;
}
}
if (cols > 0) {
lines++;
if (cols > maxcols) maxcols = cols;
}
(void) fclose (fp);
*width = maxcols;
*height = lines;
}
/*
* strip quotes from button names
*/
static void unquote_pairs (br, n)
register ButtonRecord *br;
int n;
{
int i;
for (i = 0; i < n; i++) {
register char *dst, *src;
register int quoted = 0;
for (src = dst = br->name; *src; src++) {
if (quoted) {
*dst++ = *src;
quoted = 0;
} else if (src[0] == '\\') {
quoted = 1;
} else {
*dst++ = *src;
}
}
*dst = '\0';
}
return;
}
/*
* parses string of form "yes:1,no:2, ..."
* sets brptr to point to parsed table
* returns 0 if successful, -1 if not
*/
static int parse_name_and_exit_code_list (buttonlist, brptr)
char *buttonlist;
ButtonRecord **brptr;
{
register char *cp;
int shouldfind = 0, npairs = 0;
int default_exitcode = 100;
int quoted = 0;
ButtonRecord *br;
int len;
char *copy;
if (!buttonlist) return 0;
/*
* Figure out how many matches we will find so that we can preallocate
* space for button structures. If you add stripping of white space,
* make sure that you update this as well as the walking algorithm below.
*/
if (buttonlist[0]) shouldfind++;
for (cp = buttonlist; *cp; cp++) {
if (quoted == 1) quoted = 0;
else if (*cp == '\\') quoted = 1;
else if (*cp == ',') shouldfind++;
}
len = (cp - buttonlist);
/*
* allocate space for button record
*/
br = (ButtonRecord *) malloc (sizeof(ButtonRecord) * shouldfind);
if (!br) return -1;
cp = malloc (len + 1);
if (!cp) {
(void) free ((char *) br);
return -1;
}
copy = cp;
strcpy (copy, buttonlist);
/*
* walk down list separating into name:exitcode pairs
*/
while (*cp) {
char *start, *colon, *comma;
int exitcode;
start = cp;
colon = comma = NULL;
exitcode = ++default_exitcode;
quoted = 0;
/* find the next name and exit code */
for (; *cp; cp++) {
if (quoted) quoted = 0;
else if (*cp == '\\') quoted = 1;
else if (*cp == ':') colon = cp;
else if (*cp == ',') {
comma = cp;
break;
}
}
/*
* If comma is NULL then we are at the end of the string. If colon
* is NULL, then there was no exit code given, so default to zero.
*/
if (comma) *comma = '\0';
if (colon) {
exitcode = atoi (colon+1);
*colon = '\0';
}
/*
* make sure that we aren't about to stomp on memory
*/
if (npairs >= shouldfind) {
fprintf (stderr,
"%s: internal error, found extra pairs (should be %d)\n",
ProgramName, shouldfind);
(void) free ((char *) br);
(void) free (copy);
return -1;
}
/*
* got it! start and exitcode contain the right values
*/
br[npairs].name = start;
br[npairs].exitstatus = exitcode;
npairs++;
if (comma) cp++;
}
if (npairs != shouldfind) {
fprintf (stderr, "%s: internal error found %d instead of %d pairs\n",
ProgramName, npairs, shouldfind);
(void) free ((char *) br);
(void) free (copy);
return -1;
}
/*
* now, strip any quoted characters
*/
unquote_pairs (br, npairs);
*brptr = br;
return npairs;
}
/*
* callback to handle button being pressed
*/
/* ARGSUSED */
static void handle_button (w, closure, client_data)
Widget w;
XtPointer closure;
XtPointer client_data;
{
ButtonRecord *br = (ButtonRecord *) closure;
if (br->print_value) printf("%s\n", br->name);
if (br->filename) (void) unlink(br->filename);
exit (br->exitstatus);
}
Widget make_queryform(parent, msgstr, filename, button_list,
print_value, default_button, warp_button,
columns, min_columns, max_columns,
lines, min_lines, max_lines)
Widget parent; /* into whom widget should be placed */
char *msgstr; /* message string or NULL */
char *filename; /* file name or NULL */
char *button_list; /* list of button title:status */
Boolean print_value; /* print button string on stdout? */
char *default_button; /* button activated by Return */
char *warp_button; /* button to warp cursor to */
int columns; /* requested size of message box */
int min_columns; /* min size of message box */
int max_columns; /* max size of message box */
int lines; /* requested size of message box */
int min_lines; /* min size of message box */
int max_lines; /* max size of message box */
{
ButtonRecord *br;
int npairs, i;
Widget form, text, prev;
Arg args[20];
Cardinal n, thisn;
int width, height;
int msg_lines, msg_columns;
int font_width, font_height;
Dimension old_width, old_height;
char *unlink_filename;
XFontStruct *font;
Dimension borderWidth;
Position topMargin, bottomMargin, leftMargin, rightMargin;
Widget warp_button_widget = NULL;
int default_button_index = -1;
int warp_button_index = -1;
npairs = parse_name_and_exit_code_list (button_list, &br);
form = XtCreateManagedWidget ("form", formWidgetClass, parent, NULL, 0);
n = 0;
XtSetArg (args[n], XtNleft, XtChainLeft); n++;
XtSetArg (args[n], XtNright, XtChainRight); n++;
XtSetArg (args[n], XtNtop, XtChainTop); n++;
XtSetArg (args[n], XtNbottom, XtChainBottom); n++;
XtSetArg (args[n], XtNresizable, TRUE); n++;
if (filename) {
if (*filename == '-') unlink_filename = filename = copy_stdin ();
(void) get_file_dimensions(filename, &msg_columns, &msg_lines);
XtSetArg (args[n], XtNstring, filename); n++;
XtSetArg (args[n], XtNtype, XawAsciiFile); n++;
}
else {
if (!msgstr) msgstr = "xmessage called with no message string";
(void) get_message_dimensions(msgstr, &msg_columns, &msg_lines);
XtSetArg (args[n], XtNstring, msgstr); n++;
XtSetArg (args[n], XtNtype, XawAsciiString); n++;
}
XtSetArg (args[n], XtNscrollHorizontal, XawtextScrollWhenNeeded); n++;
XtSetArg (args[n], XtNscrollVertical, XawtextScrollWhenNeeded); n++;
text = XtCreateManagedWidget ("text", asciiTextWidgetClass, form, args, n);
/*
* Interrogate the text widget to find out which font it is using,
* so we can determine the dimensions of its character cell in order
* to resize the text widget.
*
* Note that if the user has explicitly specified a geometry then
* this resizing is for naught.
*/
n = 0;
XtSetArg (args[n], XtNborderWidth, &borderWidth); n++;
XtSetArg (args[n], XtNtopMargin, &topMargin); n++;
XtSetArg (args[n], XtNbottomMargin, &bottomMargin); n++;
XtSetArg (args[n], XtNleftMargin, &leftMargin); n++;
XtSetArg (args[n], XtNrightMargin, &rightMargin); n++;
XtSetArg (args[n], XtNwidth, &old_width); n++;
XtSetArg (args[n], XtNheight, &old_height); n++;
XtSetArg (args[n], XtNfont, &font); n++;
XtGetValues(text, args, n);
font_width = font->max_bounds.width;
font_height = font->ascent + font->descent;
width = 0;
height = 0;
if (columns == 0) { /* no explicit columns on command line */
columns = msg_columns; /* use actual columns in the message */
if (columns < min_columns) columns = min_columns;
if (columns > max_columns) {
columns = max_columns;
height += SCROLLBAR_HEIGHT;
}
}
width += columns * font_width;
width += borderWidth + leftMargin + rightMargin + borderWidth;
if (lines == 0) { /* no explicit lines on command line */
lines = msg_lines; /* use actual lines in the message */
if (lines < min_lines) lines = min_lines;
if (lines > max_lines) {
lines = max_lines;
width += SCROLLBAR_WIDTH;
}
}
height += lines * font_height;
height += borderWidth + topMargin + bottomMargin + borderWidth;
if (width < old_width) width = old_width;
if (height < old_height) height = old_height;
n = 0;
XtSetArg (args[n], XtNwidth, (Dimension) width); n++;
XtSetArg (args[n], XtNheight, (Dimension) height); n++;
XtSetValues(text, args, n);
/*
* Create the buttons
*/
n = 0;
XtSetArg (args[n], XtNleft, XtChainLeft); n++;
XtSetArg (args[n], XtNright, XtChainLeft); n++;
XtSetArg (args[n], XtNtop, XtChainBottom); n++;
XtSetArg (args[n], XtNbottom, XtChainBottom); n++;
XtSetArg (args[n], XtNfromVert, text); n++;
XtSetArg (args[n], XtNvertDistance, 5); n++;
prev = NULL;
for (i = 0; i < npairs; i++) {
thisn = n;
XtSetArg (args[thisn], XtNfromHoriz, prev); thisn++;
prev = XtCreateManagedWidget (br[i].name, commandWidgetClass,
form, args, thisn);
br[i].widget = prev;
br[i].print_value = print_value;
br[i].filename = unlink_filename;
XtAddCallback (prev, XtNcallback, handle_button, (XtPointer) &br[i]);
if (default_button && !strcmp(default_button, br[i].name))
default_button_index = i;
if (warp_button && !strcmp(warp_button, br[i].name))
warp_button_index = i;
}
/*
* if we didn't find a warp button, possibly the default button
* is also the warp button
*/
if (warp_button_index < 0 && default_button_index >= 0 &&
warp_button != NULL && !strcmp(warp_button,"default")) {
warp_button_index = default_button_index;
}
/*
* if there is a default button, double its border width, then adjust
* the vertical distance of all other buttons to maintain alignment
* with the default button
*/
if (default_button_index >= 0) {
Dimension old_border, new_border;
default_button_widget = br[default_button_index].widget;
XtVaGetValues(default_button_widget, XtNborderWidth, &old_border, NULL);
new_border = old_border * 2;
XtVaSetValues(default_button_widget, XtNborderWidth, new_border, NULL);
for (i = 0; i < npairs; i++) {
if (i != default_button_index) {
int vertdistance;
XtVaGetValues(br[i].widget, XtNvertDistance, &vertdistance, NULL);
vertdistance += old_border;
XtVaSetValues(br[i].widget, XtNvertDistance, vertdistance, NULL);
}
}
}
else if (default_button != NULL && *default_button != '\0') {
fprintf(stderr, "%s: no such default button '%s'\n",
ProgramName, default_button);
}
/*
* if there is a warp button, set up an exposure handler to do the warp
*/
if (warp_button_index >= 0) {
warp_button_widget = br[warp_button_index].widget;
XtAddEventHandler(warp_button_widget, ExposureMask, False,
(XtEventHandler)warp_to_button, (XtPointer) &br[warp_button_index]);
}
else if (warp_button != NULL && *warp_button != '\0') {
fprintf(stderr, "%s: no such warp button '%s'\n",
ProgramName, warp_button);
}
return form;
}